﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Threading;

namespace WorkNodeFramework
{
    public class WorkNodePropertyCollection<P> : IEnumerable<P>
        where P : WorkNodeProperties
    {
        ITable table;
        List<P> properties = new List<P>();
        WorkNode workNode;
        object _oLock = new object();

        internal WorkNodePropertyCollection(WorkNode workNode)
        {
            this.workNode = workNode;   
        }

        internal ITable Table
        {
            get { 
                if(table==null && WorkNode.WorkPart!=null)
                    table = WorkNode.Provider.GetTable(WorkNode.WorkPart.Properties);
                return table;
            }
        }

        public string this[string Name]
        {
            get
            {
                return Get<string>(Name);
            }
            set
            {
                Set(Name, value);
            }
        }

        protected WorkNode WorkNode {
            get {
                return workNode;
            }
        }

        P GetPropertyWithoutLock(string Name, bool createNewIfNotExist)
        {
            P p = properties.Find(delegate(P match)
            {
                return match.Name == Name;
            });

            if (p != null)
                return p;

            if (!workNode.IsNew && Table != null)
            {
                Select select = new Select(workNode.Provider)
                    .From(Table)
                    .Where(WHERE.AND(
                        WHERE.DO(Table["WorkNodeID"]).IsEqualsTo(workNode.ID),
                        WHERE.DO(Table["Name"]).IsEqualsTo(Name))
                     );

                p = select.ExecuteEntity<P>();
            }

            if (p != null)
            {
                properties.Add(p);
                return p;
            }

            if (createNewIfNotExist)
            {
                p = (P)Activator.CreateInstance(typeof(P));
                p.Name = Name;
                p.WorkNodeID = workNode.ID;
                properties.Add(p);
            }

            return p;
        }

        protected P GetProperty(string Name, bool createNewIfNotExist)
        {
            lock (_oLock)
            {
                return GetPropertyWithoutLock(Name, createNewIfNotExist);
            }
        }

        public T Get<T>(string Name)
        {
            return Get<T>(Name, default(T));
        }

        public T Get<T>(string Name, T defaultValue)
        {
            P p = GetProperty(Name, false);
            if (p == null)
                return defaultValue;
            return StringParser.Parse<T>(p.Content, defaultValue);
        }

        void SetWithoutLock(string Name, object Value) {
            P p = GetPropertyWithoutLock(Name, true);
            p.Content = StringParser.ConvertToString(Value);
        }

        public void Set(string Name, object Value)
        {
            P p = GetProperty(Name, true);
            p.Content = StringParser.ConvertToString(Value);
        }

        public void Load()
        {
            if (workNode.IsNew)
                return;
            lock (_oLock)
            {
                List<P> items = new Select(workNode.Provider)
                     .From(Table)
                     .Where(WHERE.DO(Table["WorkNodeID"]).IsEqualsTo(workNode))
                     .ExecuteTypedList<P>();
                foreach (P p in items)
                    SetWithoutLock(p.Name, p.Content);
            }
        }

        public void Clear()
        {
            lock (_oLock)
            {
                properties.Clear();
            }
        }

        public bool Remove(string Name)
        {
            lock (_oLock)
            {
                P p = GetPropertyWithoutLock(Name, false);
                if (p != null)
                  return properties.Remove(p);
                return false;
            }
        }

        public bool Delete(string Name)
        {
            lock (_oLock)
            {
                P p = GetPropertyWithoutLock(Name, false);
                if (p != null)
                {
                    ((IFieldSet)p).DefaultStatus = FieldSetStatus.Deleted;
                    return true;
                }
                return false;
            }
        }

        #region IEnumerable<T> Members

        public IEnumerator<P> GetEnumerator()
        {
            lock (_oLock)
            {
                return properties.GetEnumerator();
            }
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            lock (_oLock)
            {
                return ((IEnumerable)properties).GetEnumerator();
            }
        }

        #endregion
    }

    public class WorkNodeLangPropertyCollection<P> : IEnumerable<P>
        where P : WorkNodeLangProperties
    {
        ITable table;
        List<P> properties = new List<P>();
        WorkNode workNode;
        string defaultLanguage = null;
        object _oLock = new object();

        internal WorkNodeLangPropertyCollection(WorkNode workNode, string language)
        {
            this.workNode = workNode;
            this.defaultLanguage = language;
        }

        internal ITable Table
        {
            get {
                if (table == null && WorkNode.WorkPart != null)
                    table = WorkNode.Provider.GetTable(WorkNode.WorkPart.LangProperties);
                return table;
            }
        }

        public string this[string Name, string Lang]
        {
            get
            {
                return Get<string>(Name, Lang);
            }
            set
            {
                Set(Name, Lang, value);
            }
        }

        protected WorkNode WorkNode
        {
            get
            {
                return workNode;
            }
        }

        public string Language
        {
            get
            {
                if (defaultLanguage == null)
                    return Thread.CurrentThread.CurrentUICulture.Name;
                return defaultLanguage;
            }
            set
            {
                defaultLanguage = value;
            }
        }

        protected P GetProperty(string Name, string Lang, bool createNewIfNotExist)
        {
            lock (_oLock)
            {
                return GetPropertyWithoutLock(Name, Lang, createNewIfNotExist);
            }
        }

        P GetPropertyWithoutLock(string Name, string Lang, bool createNewIfNotExist)
        {
            string lang = Lang;
            if (string.IsNullOrEmpty(lang))
                lang = Language;

            P p = properties.Find(delegate(P match)
            {
                return match.Name == Name && match.LangID == lang;
            });

            if (p != null)
                return p;

            if (!workNode.IsNew && Table != null)
            {
                Select select = new Select(workNode.Provider)
                    .From(Table)
                    .Where(WHERE.AND(
                        WHERE.DO(Table["WorkNodeID"]).IsEqualsTo(workNode.ID),
                        WHERE.DO(Table["Name"]).IsEqualsTo(Name),
                        WHERE.DO(Table["LangID"]).IsEqualsTo(lang))
                     );

                p = select.ExecuteEntity<P>();
            }

            if (p != null)
            {
                properties.Add(p);
                return p;
            }

            if (createNewIfNotExist)
            {
                p = (P)Activator.CreateInstance(typeof(P));
                p.Name = Name;
                p.LangID = lang;
                p.WorkNodeID = workNode.ID;
                properties.Add(p);
            }

            return p;
        }

        public T Get<T>(string Name, string Lang)
        {
            return Get<T>(Name, Lang, default(T));
        }

        public T Get<T>(string Name, string Lang, T defaultValue)
        {
            P p = GetProperty(Name, Lang, false);
            if (p == null)
                return defaultValue;
            return StringParser.Parse<T>(p.Content, defaultValue);
        }

        public void Set(string Name, string Lang, object Value)
        {
            P p = GetProperty(Name, Lang, true);
            p.Content = StringParser.ConvertToString(Value);
        }

        void SetWithoutLock(string Name, string Lang, object Value)
        {
            P p = GetPropertyWithoutLock(Name, Lang, true);
            p.Content = StringParser.ConvertToString(Value);
        }

        public void Load()
        {
            Load(defaultLanguage);
        }

        public void Load(string Lang)
        {
            lock (_oLock)
            {
                string lang = Lang;
                if (string.IsNullOrEmpty(lang))
                    lang = Language;

                List<P> items = null;
                Select select = new Select(workNode.Provider)
                     .From(Table)
                     .Where
                     (
                        WHERE.DO(Table["WorkNodeID"]).IsEqualsTo(workNode),
                        WHERE.DO(Table["LangID"]).IsEqualsTo(lang)
                     );

                items = select.ExecuteTypedList<P>();
                foreach (P p in items)
                    SetWithoutLock(p.Name, Lang, p.Content);
            }
        }

        public bool Remove(string Name, string Lang)
        {
            lock (_oLock)
            {
                P p = GetPropertyWithoutLock(Name, Lang, false);
                if (p != null)
                    return properties.Remove(p);
                return false;
            }
        }

        public bool Delete(string Name, string Lang)
        {
            lock (_oLock)
            {
                P p = GetPropertyWithoutLock(Name, Lang, false);
                if (p != null)
                {
                    ((IFieldSet)p).DefaultStatus = FieldSetStatus.Deleted;
                    return true;
                }
                return false;
            }
        }

        #region IEnumerable<T> Members

        public IEnumerator<P> GetEnumerator()
        {
            lock (_oLock)
            {
                return properties.GetEnumerator();
            }
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            lock (_oLock)
            {
                return ((IEnumerable)properties).GetEnumerator();
            }
        }

        #endregion
    }
}
